package com.husd.framework.autocode;

import com.alibaba.fastjson.JSON;
import com.husd.framework.autocode.dto.ClassDefine;
import com.husd.framework.autocode.dto.ClassFieldDefine;
import com.husd.framework.autocode.dto.XmlDefine;
import com.husd.framework.ddl.AutoCodeUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * @author shengdonghu@126.com
 * @date 2023/4/23 18:08
 */
public class Ebay03ClassDefineConvert {

    Stack<XmlDefine> stack = new Stack<>();
    XmlDefine preXmlDefine = null;

    public Ebay03ClassDefineConvert(XmlDefine xmlDefine) {

        stack.push(xmlDefine);
    }

    private XmlDefine pop() {

        XmlDefine xmlDefine = stack.pop();
        return xmlDefine;
    }

    private String CLASS_NAME_PRE = "OpenSdkEbayAddItem";

    public List<ClassDefine> convert() {

        if (stack.isEmpty()) {
            return new ArrayList<>();
        }
        XmlDefine xmlDefine = pop();
        List<ClassDefine> res = new ArrayList<>();
        ClassDefine classDefine = new ClassDefine();

        classDefine.setClassName(className(xmlDefine));
        classDefine.setClassType("class");
        classDefine.setAnnotationList(defaultAnnotation(xmlDefine.getName()));

        // 先写入属性的值 属性不能重复
        List<XmlDefine.XmlAttrDefine> attrList =
                xmlDefine.getAttrList();
        if (CollectionUtils.isNotEmpty(attrList)) {
            List<ClassFieldDefine> fieldList = new ArrayList<>();
            for (XmlDefine.XmlAttrDefine attr : attrList) {
                if(attr.getName().startsWith("xmlns")  && attr.getValue().trim().startsWith("http")) {
                    //System.out.println("忽略了命名空间:" + JSON.toJSONString(attr));
                    continue;
                }
                ClassFieldDefine stringField = defaultStringField(xmlDefine, attr);
                fieldList.add(stringField);
            }
            classDefine.setFieldList(fieldList);
        }

        // 再设置元素的值 元素是有可能可以重复的
        List<XmlDefine> elementList = xmlDefine.getElementList();
        boolean repeat = xmlDefine.isRepeat();
        // 这种要看有几个元素 如果有多个元素 就递归处理
        // 如果没有子元素 就需要特殊处理
        if (CollectionUtils.isNotEmpty(elementList)) {
            List<ClassFieldDefine> fieldList = classDefine.getFieldList();
            if (fieldList == null) {
                fieldList = new ArrayList<>();
            }
            for (XmlDefine element : elementList) {
                // 要考虑这个元素 是不是可以有多个
                ClassFieldDefine classFieldDefine = defaultElementField(element);
                fieldList.add(classFieldDefine);
                stack.push(element);
            }
            classDefine.setFieldList(fieldList);
        } else {
            // 要考虑这个元素 是不是可以有多个
            ClassFieldDefine classFieldDefine = defaultElementFieldJacksonXmlText(xmlDefine, repeat);
            List<ClassFieldDefine> fieldList = classDefine.getFieldList();
            if (fieldList == null) {
                fieldList = new ArrayList<>();
            }
            fieldList.add(classFieldDefine);
            classDefine.setFieldList(fieldList);
        }
        res.add(classDefine);
        if (stack.isEmpty() == false) {
            List<ClassDefine> resres = convert();
            if (CollectionUtils.isNotEmpty(resres)) {
                res.addAll(resres);
            }
        }

        // 增加注解 OpenJsonPath
        return res;
    }

    private ClassFieldDefine defaultElementField(XmlDefine element) {

        boolean repeat = element.isRepeat();
        String localName = element.getName();
        boolean complex = false;
        String annotation = "";
        String fieldName = "";
        String fieldType = "";

        XmlDefine.XmlDefineType xmlDefineType = element.getType();
        String type = xmlDefineType.getType();
        if (StringUtils.isBlank(type)) {
            // 空就是说明是复合类型 需要是类 类的名字需要单独处理 生成
            type = className(element);
            complex = true;
        } else {
            complex = false;
        }
        if (repeat) {
            StringBuilder sb = new StringBuilder();
            sb.append("@JacksonXmlElementWrapper(useWrapping = false)");
            sb.append("\n");
            sb.append("@JacksonXmlProperty(localName = \"" + localName + "\")");
            annotation = sb.toString();
        } else {
            annotation = "@JacksonXmlProperty(localName = \"" + localName + "\")";
        }
        fieldName = AutoCodeUtil.firstLowerCase(localName);
        // 如果是可以重复的 就是一个List
        if (repeat) {
            type = String.format("List<%s>", type);
        }
        fieldType = type;

        //annotation = annotation + "\n " + createOpenJsonPath(element);
        return createClassFieldDefine(fieldType, fieldName, annotation, "", complex, "", "", "");
    }

    private String createOpenJsonPath(XmlDefine xmlDefine) {

        String t = "@OpenJsonPath(path = \"%s\")";
        return String.format(t, xmlDefine.getPath());
    }

    private String createOpenJsonPath(XmlDefine xmlDefine, String attrName) {

        String t = "@OpenJsonPath(path = \"%s\")";
        return String.format(t, xmlDefine.getPath()+":" + attrName);
    }

    private ClassFieldDefine defaultElementFieldJacksonXmlText(XmlDefine xmlDefine, boolean repeat) {

        String annotation = "@JacksonXmlText \n";
        //annotation = annotation + createOpenJsonPath(xmlDefine);
        ClassFieldDefine classFieldDefine = createClassFieldDefine("String", "value", annotation, "", false,
                "", "", "");
        return classFieldDefine;
    }

    private String className(XmlDefine xmlDefine) {

        if (xmlDefine == null) {
            return "UnknownName";
        }

        String name = xmlDefine.getName();
        // 这里做一些加工 预防某些名字是java的关键字
        if (name.contains(".")) {
            name = name.replaceAll("\\.", "");
        }
        String[] keyArr = {"string", "int", "short", "float", "double", "byte", "long", "char", "bigdecimal"};
        for (String keyName : keyArr) {

            String name1 = name.toLowerCase();
            if (StringUtils.equals(keyName, name1)) {
                return className(xmlDefine.getParentXmlDefine()) + AutoCodeUtil.firstUpper(name1);
            }
        }
        return name;
    }

    private ClassFieldDefine defaultStringField(XmlDefine xmlDefine, XmlDefine.XmlAttrDefine attr) {

        ClassFieldDefine classFieldDefine = defaultField(xmlDefine, attr, "String");
        classFieldDefine.setComplex(false);
        return classFieldDefine;
    }

    private ClassFieldDefine defaultField(XmlDefine xmlDefine, XmlDefine.XmlAttrDefine attr, String type) {

        String localName = attr.getName();

        String annotation = "@JacksonXmlProperty(localName = \"" + localName + "\", isAttribute = true)";
        //annotation = annotation + "\n" + createOpenJsonPath(xmlDefine, localName);
        String fieldName = localName;
        String classTypeName = AutoCodeUtil.name2JavaClassName(fieldName);

        ClassFieldDefine classFieldDefine = createClassFieldDefine(type, localName, annotation, "", false, "", classTypeName, "");
        return classFieldDefine;
    }

    private ClassFieldDefine createClassFieldDefine(String fieldType, String fieldName,
                                                    String fieldAnno, String comments,
                                                    boolean complex, String ext,
                                                    String classTypeName, String originJsonName) {

        ClassFieldDefine classFieldDefine = new ClassFieldDefine();

        classFieldDefine.setFieldType(fieldType);
        classFieldDefine.setFieldName(fieldName);
        classFieldDefine.setFieldAnnotation(fieldAnno);
        classFieldDefine.setComment(comments);
        classFieldDefine.setComplex(complex);
        classFieldDefine.setExt(ext);
        classFieldDefine.setClassTypeName(classTypeName);
        classFieldDefine.setOriginJsonName(originJsonName);

        if (StringUtils.isBlank(classFieldDefine.getClassTypeName())) {
            classFieldDefine.setClassTypeName(AutoCodeUtil.name2JavaClassName(fieldName));
        }

        return classFieldDefine;
    }

    private List<String> defaultAnnotation(String localName) {

        List<String> res = new ArrayList<>();

        res.add("@Data");
        res.add("@JacksonXmlRootElement(localName = \"" + localName + "\")");
        return res;
    }

}
